package com.google.code.mochaccino.framework.hibernate.provider.configuration;
/*
 * Copyright 2012 Claude Houle claude.houle@gmail.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import com.google.code.mochaccino.framework.hibernate.provider.configuration.helper.ConfigurationHelper;
import com.google.code.mochaccino.framework.hibernate.provider.configuration.helper.ConfigurationHelperBatch;
import com.google.code.mochaccino.framework.hibernate.provider.configuration.helper.ConfigurationHelperCache;
import com.google.code.mochaccino.framework.hibernate.provider.configuration.helper.ConfigurationHelperDebug;
import com.google.code.mochaccino.framework.hibernate.provider.configuration.helper.ConfigurationHelperJdbc;
import com.google.code.mochaccino.framework.hibernate.provider.configuration.helper.ConfigurationHelperTransaction;
import java.util.Properties;
import javax.inject.Provider;
import javax.persistence.Entity;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.cfg.ImprovedNamingStrategy;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.dialect.Dialect;

/** Session Factory Provider base Implementation. */
public abstract class ConfigurationProvider implements Provider<Configuration> {
	/** Dialect */
	private Class<? extends Dialect> dialect = null;

	/** Classes Configurator */
	private Class<?>[] classes = new Class<?>[0];

	/** Batch Configurator */
	private ConfigurationHelperBatch batchConfigurator = new ConfigurationHelperBatch();

	/** Cache Configurator */
	private ConfigurationHelperCache cacheConfigurator = new ConfigurationHelperCache();

	/** Debug Configurator */
	private ConfigurationHelperDebug debugConfigurator = new ConfigurationHelperDebug();

	/** JDBC Configurator */
	private ConfigurationHelperJdbc jdbcConfigurator = new ConfigurationHelperJdbc();

	/** Transaction Configurator */
	private ConfigurationHelperTransaction transactionConfigurator = ConfigurationHelperTransaction.local();

	/** Custom Configurator */
	private ConfigurationHelper customConfigurator = null;

	/** Naming Strategy */
	private NamingStrategy namingStrategy = new ImprovedNamingStrategy();

	/** Use new generator mappings (Default to true as recommended by Hibernate Documentation) */
	private boolean useNewGeneratorMappings = true;

	/** Default Batch Fetch Size (Recommended values are 4, 8, or 16 ) */
	private int defaultBatchFetchSize = 16;

	/** Max Fetch Depth (Recommended values is between 0 and 3 ) */
	private int maxFetchDepth = 3;

	@Override
	public final Configuration get() {
		Properties properties = new Properties();
		configure( properties );

		Configuration configuration = new Configuration();
		configuration.setProperties( properties );
		if ( namingStrategy != null ) {
			configuration.setNamingStrategy( namingStrategy );
		}

		if ( classes != null ) {
			for ( Class<?> c : classes ) {
				if ( c.getAnnotation( Entity.class ) != null ) {
					configuration.addAnnotatedClass( c );
				}
			}
		}
		return configuration;
	}

	protected void configure( Properties p ) {
		p.put( Environment.DIALECT, dialect.getName() );
		p.put( Environment.DEFAULT_BATCH_FETCH_SIZE, String.valueOf( defaultBatchFetchSize ) );
		p.put( Environment.MAX_FETCH_DEPTH, String.valueOf( maxFetchDepth ) );
		p.put( Environment.HBM2DDL_AUTO, "none" );
		p.put( Environment.USE_NEW_ID_GENERATOR_MAPPINGS, Boolean.toString( useNewGeneratorMappings ) );
		jdbcConfigurator.configure( p );
		cacheConfigurator.configure( p );
		debugConfigurator.configure( p );
		batchConfigurator.configure( p );
		transactionConfigurator.configure( p );
		if ( customConfigurator != null ) {
			customConfigurator.configure( p );
		}
	}

	public void setBatchConfigurator( ConfigurationHelperBatch batchConfigurator ) {
		this.batchConfigurator = batchConfigurator;
	}

	public void setCacheConfigurator( ConfigurationHelperCache cacheConfigurator ) {
		this.cacheConfigurator = cacheConfigurator;
	}

	public void setClasses( Class<?>[] classes ) {
		this.classes = new Class<?>[classes.length];
		System.arraycopy( classes, 0, this.classes, 0, classes.length );
	}

	public void setCustomConfigurator( ConfigurationHelper customConfigurator ) {
		this.customConfigurator = customConfigurator;
	}

	public void setDebugConfigurator( ConfigurationHelperDebug debugConfigurator ) {
		this.debugConfigurator = debugConfigurator;
	}

	public void setDefaultBatchFetchSize( int defaultBatchFetchSize ) {
		this.defaultBatchFetchSize = defaultBatchFetchSize;
	}

	public void setDialect( Class<? extends Dialect> dialect ) {
		this.dialect = dialect;
	}

	public void setJdbcConfigurator( ConfigurationHelperJdbc jdbcConfigurator ) {
		this.jdbcConfigurator = jdbcConfigurator;
	}

	public void setMaxFetchDepth( int maxFetchDepth ) {
		this.maxFetchDepth = maxFetchDepth;
	}

	public void setNamingStrategy( NamingStrategy namingStrategy ) {
		this.namingStrategy = namingStrategy;
	}

	public void setTransactionConfigurator( ConfigurationHelperTransaction transactionConfigurator ) {
		this.transactionConfigurator = transactionConfigurator;
	}

	public void setUseNewGeneratorMappings( boolean useNewGeneratorMappings ) {
		this.useNewGeneratorMappings = useNewGeneratorMappings;
	}

	protected Class<? extends Dialect> getDialect() {
		return dialect;
	}
}
